#!/bin/sh

map_user_dirs()
{
  echo root$'\t'/var/root && \
    dscl . list /Users | \
      sed -e '/^_/d;/root/d;/nobody/d;/daemon/d' | \
      xargs -I{} dscacheutil -q user -a name {} | \
      grep ^dir | \
      cut -d' ' -f2- | \
      nl -nrz -w4
}

get_id()
{
  echo "${1}" | cut -f 1
}

get_home()
{
  echo "${1}" | cut -f 2
}

gather_displays_layout()
{
  local INFO_FOLDER="$1"
  local APP_RESOURCES_FOLDER=$(dirname "$0")
  "$APP_RESOURCES_FOLDER/../MacOS/DisplayDetails" >> "$INFO_FOLDER/Displays Details.txt"
}

gather_system_profile()
{
  local INFO_FOLDER="$1"
  local PROFILE="$INFO_FOLDER/System Profile"

  /usr/sbin/system_profiler -xml -detailLevel full > "$PROFILE.spx"
  /usr/sbin/system_profiler SPHardwareDataType SPSoftwareDataType SPNetworkDataType SPMemoryDataType SPUSBDataType \
    | sed "/Boot Volume:/d;/User Name:/d;/Computer Name:/d" > "$PROFILE.txt"
  cp "/Library/Extensions/DisplayLinkDriver.kext/Contents/Info.plist" "$INFO_FOLDER"
  echo "DisplayLinkUser agent service status:" >> "$PROFILE.txt"
  launchctl list | grep displaylink >> "$PROFILE.txt"

  local KEXT_PLIST_PRESENT="no"
  test -f "/Library/Extensions/DisplayLinkDriver.kext/Contents/Info.plist" &&  KEXT_PLIST_PRESENT="yes"
  echo "DisplayLink KEXT plist present: $KEXT_PLIST_PRESENT" >> "$PROFILE.txt"

  echo "Loaded DisplayLink KEXT (com.displaylink.driver.DisplayLinkDriver):" >> "$PROFILE.txt"
  kextstat -b com.displaylink.driver.DisplayLinkDriver >> "$PROFILE.txt"

  echo "Loaded DisplayLink KEXT with cache mitigation(com.displaylink.DisplayLinkDriver):" >> "$PROFILE.txt"
  kextstat -b com.displaylink.DisplayLinkDriver >> "$PROFILE.txt"

  local LEGACY_DL_APP_PRESENT="no"
  test -f "/Applications/DisplayLink/DisplayLink Software Uninstaller.app/Contents/Info.plist" &&  LEGACY_DL_APP_PRESENT="yes"
  echo "Legacy DisplayLink Uninstaller plist present: $LEGACY_DL_APP_PRESENT" >> "$PROFILE.txt"

  local DL_APP_PRESENT="no"
  test -f "/Applications/DisplayLink Software Uninstaller.app/Contents/Info.plist" &&  DL_APP_PRESENT="yes"
  echo "DisplayLink Uninstaller plist present: $DL_APP_PRESENT" >> "$PROFILE.txt"

  echo "ls -la /Library/Application Support/DisplayLink" >> "$PROFILE.txt"
  ls -la "/Library/Application Support/DisplayLink" >> "$PROFILE.txt"

  echo "ls -la /Library/PrivilegedHelperTools/DisplayLink" >> "$PROFILE.txt"
  ls -la "/Library/PrivilegedHelperTools/DisplayLink/" >> "$PROFILE.txt"


  echo "umask" >> "$PROFILE.txt"
  umask >> "$PROFILE.txt"

  echo "IOREG IOService:" >> "$PROFILE.txt"
  ioreg -l -x >> "$PROFILE.txt"

  echo "" >> "$PROFILE.txt"

  echo "IOREG IOUSB:" >> "$PROFILE.txt"
  ioreg -p IOUSB -lx >> "$PROFILE.txt"

  echo "" >> "$PROFILE.txt"

  echo "System-wide WindowServer plist:" >> "$PROFILE.txt"
  defaults read /Library/Preferences/com.apple.windowserver.plist >> "$PROFILE.txt"

  map_user_dirs | while read user
  do
    echo "WindowServer plist in $(get_id "${user}") user's directory:" >> "$PROFILE.txt"

    for el in "$(get_home "${user}")"/Library/Preferences/ByHost/com.apple.windowserver.*.plist
    do
      if [ -e "$el" ]
      then
        echo $(basename $el) >> "$PROFILE.txt"
        plutil -p "$el" >> "$PROFILE.txt"
        echo "" >> "$PROFILE.txt"
      fi
    done
  done

  echo "DisplayLink processes" >> "$PROFILE.txt"
  ps ax | grep DisplayLink >> "$PROFILE.txt"
}

gather_crash_dumps()
{
  local INFO_FOLDER="$1"

  map_user_dirs | while read user
  do
    local CRASHSRCDIR="$(get_home "${user}")/Library/Logs/DiagnosticReports"
    if test -d "$CRASHSRCDIR"
    then
      local CRASHDESTDIR="$INFO_FOLDER/$(get_id "${user}")/Crash Reports"
      mkdir -p "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/DisplayLink* "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/DisplayDetails* "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/replayd* "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/Retired/DisplayLink* "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/Retired/DisplayDetails* "$CRASHDESTDIR"
      cp -r "$CRASHSRCDIR"/Retired/replayd* "$CRASHDESTDIR"
    fi
  done

  if test -d '/Library/Logs/DiagnosticReports'
  then
    local ROOTCRASHDESTDIR="$INFO_FOLDER/root/Crash Reports"
    mkdir -p "$ROOTCRASHDESTDIR"
    cp -r "/Library/Logs/DiagnosticReports/DisplayLink"* "$ROOTCRASHDESTDIR"
    cp -r "/Library/Logs/DiagnosticReports/WindowServer"* "$ROOTCRASHDESTDIR"
    cp -r "/Library/Logs/DiagnosticReports/Retired/DisplayLink"* "$ROOTCRASHDESTDIR"
    cp -r "/Library/Logs/DiagnosticReports/Retired/WindowServer"* "$ROOTCRASHDESTDIR"
  fi
}

gather_user_logs()
{
  local INFO_FOLDER="$1"

  map_user_dirs | while read user
  do
    local LOGSRCDIR="$(get_home "${user}")"'/Library/Group Containers/73YQY62QM3.com.displaylink.DisplayLinkShared/Library/Application Support/Logs'
    if test -d "${LOGSRCDIR}"
    then
      local LOGDESTDIR="$INFO_FOLDER/$(get_id "${user}")"
      mkdir -p "$LOGDESTDIR"
      cp "${LOGSRCDIR}/"*.edid "$LOGDESTDIR"
      cp "${LOGSRCDIR}/"*.log "$LOGDESTDIR"
      cp "${LOGSRCDIR}/.dl.xml" "$LOGDESTDIR/dl.xml"
      cp "${LOGSRCDIR}/.dlua.xml" "$LOGDESTDIR/dlua.xml"
      
      defaults export com.displaylink.DisplayLinkUserAgent "${LOGDESTDIR}/defaults.plist"
      
      local ROTATIONPREFS="$(get_home "${user}")"'/Library/Group Containers/73YQY62QM3.com.displaylink.DisplayLinkShared/Library/Preferences/73YQY62QM3.com.displaylink.DisplayLinkShared.plist'
      if test -f "${ROTATIONPREFS}"
      then
        cp "${ROTATIONPREFS}" "$LOGDESTDIR/rotation.plist"
      fi
    fi
  done

  local LEGACYLOGDIR="/Library/Application Support/DisplayLink"

  if test -d "$LEGACYLOGDIR"
  then
    local LEGACYLOGDESTDIR="$INFO_FOLDER/legacy"
    mkdir -p "$LEGACYLOGDESTDIR"
    cp "${LEGACYLOGDIR}/"*.edid "$LEGACYLOGDESTDIR/"
    cp "${LEGACYLOGDIR}/"*.log "$LEGACYLOGDESTDIR/"
    cp "${LEGACYLOGDIR}/.dl.xml" "$LEGACYLOGDESTDIR/dl.xml"
    cp "${LEGACYLOGDIR}/.dlua.xml" "$LEGACYLOGDESTDIR/dlua.xml"
  fi
}

readonly DEST_FILE="$1"
readonly GATHER_FOLDER="$(mktemp -d)"

if cd "$GATHER_FOLDER"
then
  gather_system_profile .
  gather_crash_dumps .
  gather_user_logs .
  gather_displays_layout .

  zip -r "$DEST_FILE".intermediate.zip ./ && \
  mv -f "$DEST_FILE".intermediate.zip "$DEST_FILE"

  rm -rf "$GATHER_FOLDER"
fi
